/*
 * @Author: quit
 * @Date: 2023-03-08 16:18:29
 * @LastEditTime: 2023-03-08 19:05:14
 * @Descripttion: TS中的高级类型
 * @notice:
 */

/**
 * @description: 联合类型
 * 取值可以为多种类型中的一种,使用竖线（ | ） 分割每一个类
 * 联合类型的属性或方法,只能访问它的所有类型里共有的属性或方法
 */
let c1: number | string;
c1 = 1;
c1 = '1';
function getParam(param: number | string): number | string {
    // console.log(param.toFixed(1)); // error 只可以使用number 和 string 原型上共有的方法
    // console.log(param.toString()); // success
    return param;
}
getParam(1);
getParam('1');
getParam(1.234);

/**
 * @description: 类型推论
 * 在TS里,有些没有明确指出类型的地方,类型推论会帮助提供类型
 * 发生条件: 在初始化变量和成员，设置默认参数和决定函数返回值时
 * 如果在定义时没有进行初始化,那么这个变量的类型就是any,跳过TS类型检查
 */
let v1 = 3;
// v1 = 'string'; // 这里无法将其赋值为字符串
// function getName(param) {
//     // param为any func为void
//     console.log(param);
//     return param;
// }
let v2;
v2 = 1;
v2 = '1';

/**
 * @description: 类型断言
 * 可以用来手动指定一个值的类型
 * <类型>值 | 值 as 类型  在JSX中为了避免JSX语法冲突只能使用第二种
 * 类型断言中较为突出的是 双重断言的使用场景
 */
// function fn(param: number | string): number {
//     return (<string>param).length;
// }
// console.log(fn('hello'));
// console.log(fn(1)); // undefined
// 在适用类型断言时请注意,这是一个危险行为,作为使用者需要清晰的知道每一个类型在判断时他的类型才能进行强行手动指定
function fn(param: number | string): number {
    if (typeof param === 'string') {
        return (<string>param).length;
    } else {
        return (<string>param.toString()).length;
    }
}
console.log(fn(1)); // 1

let x: number | string;
x = 12;
// let y = x as any as string;
let y = x as Object as string; // 可以使当前变量跳过类型检查

/**
 * @description: 类型别名
 * 用来给一个类型起一个新名字
 * 并不会创建一个新的类型
 * 作为了解性知识点
 */
let v3: number = 1;
type Name = number;
let v4: Name = 2;
type NameNS = number | string;
let v5: NameNS = '1';

/**
 * @description: 字符串字面量类型
 * 用来约束只能是一些字符串中的一个
 * 同样使用 type 进行定义
 * TS同样提供 boolean 和 number 的字面量类型
 */

type MoveDirection = 'up' | 'down' | 'left' | 'right';
function move(param: MoveDirection): void {
    console.log(param);
}
// move(123);
move('up');

type MyNum = 1 | 2 | 3;
// let v6: MyNum = 4;

export {}; // 给文件添加一个导出避免出现不同文件的重复命名
